/* This code is restricted under LGPL license */
using NHibernate.Criterion;

namespace infoMECHANICA.NHibernateORM.CriteriaBuilder
{
    /// <summary>
    /// Join between left and right (primary/secondary) criterions
    /// </summary>
    /// <typeparam name="T">Base property type</typeparam>
    public class CriterionJoin<T> : PropertyNameHolder, ICriterionSource, ICriterionJoin<T>
    {        
        private CriterionPropertyInternal<T> criterionPropertyInternal;
        private CriterionJoinTypes criterionJoinType;

        /// <summary>
        /// Selected type of criterion join
        /// </summary>
        public CriterionJoinTypes CriterionJoinType
        {
            get { return criterionJoinType; }
            set { criterionJoinType = value; }
        }

        /// <summary>
        /// Internal criterion property (passed by)
        /// </summary>
        protected CriterionPropertyInternal<T> CriterionPropertyInternal
        {
            get { return criterionPropertyInternal; }
            set { criterionPropertyInternal = value; }
        }

        /// <summary>
        /// Passes internal criterion property
        /// </summary>
        /// <returns>Internal criterion property</returns>
        private CriterionPropertyInternal<T> PassBy()
        {
            this.CriterionPropertyInternal = new CriterionPropertyInternal<T>(this.PropertyName);
            return this.CriterionPropertyInternal;
        }

        /// <summary>
        /// <see>ICriterionPropertyInternal</see> interface summary
        /// </summary>
        public ICriterionPropertyInternal<T> And
        {
            get
            {
                this.CriterionJoinType = CriterionJoinTypes.And;
                return PassBy();
            }
        }

        /// <summary>
        /// <see>ICriterionPropertyInternal</see> interface summary
        /// </summary>
        public ICriterionPropertyInternal<T> Or
        {
            get
            {
                this.CriterionJoinType = CriterionJoinTypes.Or;
                this.CriterionPropertyInternal = new CriterionPropertyInternal<T>(this.PropertyName);
                return this.CriterionPropertyInternal;
            }
        }

        /// <summary>
        /// Constructor, sets PropertyName
        /// </summary>
        /// <param name="propertyName">PropertyName to set</param>
        public CriterionJoin(string propertyName) : base(propertyName)
        {
            this.CriterionJoinType = CriterionJoinTypes.None;            
        }

        /// <summary>
        /// <see>ICriterionSource</see> interface summary
        /// </summary>
        public ICriterion GetCriterion()
        {
            if (this.CriterionJoinType != CriterionJoinTypes.None)
            {
                return this.CriterionPropertyInternal.GetCriterion();
            }

            return null;
        }
    }
}
